//
//  MSDataBaseModel.m
//  MSDemo
//
//  Created by ms on 2024/1/30.
//

#import "MSDataBaseModel.h"
#import <objc/runtime.h>

#define primaryId   @"pk"
/** SQLite五种数据类型 */
#define PrimaryKey  @"PRIMARY KEY AUTOINCREMENT"  // 主键自动增长
#define SQLTEXT     @"TEXT" // 用于存储字符串
#define SQLINTEGER  @"INTEGER"  // 用于存储整数
#define SQLREAL     @"REAL" // 于存储浮点数
#define SQLBLOB     @"BLOB" // 用于存储二进制数据
#define SQLNULL     @"NULL" // 表示该列的值为空

@interface MSDataBaseModel ()

@end

@implementation MSDataBaseModel

#pragma mark - override method
+ (void)initialize
{
    if (self != [MSDataBaseModel self]) 
    {
        [self ms_createTable];
    }
}

- (instancetype)init
{
    self = [super init];
    
    if (self)
    {
        NSDictionary *dic = [self.class ms_getAllProperties];
        _columeNames = [[NSMutableArray alloc] initWithArray:[dic objectForKey:@"name"]];
        _columeTypes = [[NSMutableArray alloc] initWithArray:[dic objectForKey:@"type"]];
    }
    
    return self;
}

#pragma mark - base method
#pragma mark - util method
/** 获取类的属性和类型 */
- (NSString *)description
{
    NSString *result = @"";
    NSDictionary *dict = [self.class ms_getAllProperties];
    NSMutableArray *proNames = [dict objectForKey:@"name"];
    
    for (int i = 0; i < proNames.count; i++)
    {
        NSString *proName = [proNames objectAtIndex:i];
        id  proValue = [self valueForKey:proName];
        result = [result stringByAppendingFormat:@"%@:%@\n",proName,proValue];
    }
    
    return result;
}
/** 获取类的属性和类型，用于建表 */
+ (NSString *)getColumeAndTypeString
{
    NSMutableString* pars = [NSMutableString string];
    NSDictionary *dict = [self.class ms_getAllProperties];
    
    NSMutableArray *proNames = [dict objectForKey:@"name"];
    NSMutableArray *proTypes = [dict objectForKey:@"type"];
    
    for (int i=0; i< proNames.count; i++)
    {
        [pars appendFormat:@"%@ %@",[proNames objectAtIndex:i],[proTypes objectAtIndex:i]];
        
        if(i+1 != proNames.count)
        {
            [pars appendString:@","];
        }
    }
    
    return pars;
}
/**
 *  获取该类的所有属性
 */
+ (NSDictionary *)ms_getPropertys
{
    NSMutableArray *proNames = [NSMutableArray array];
    NSMutableArray *proTypes = [NSMutableArray array];
    NSArray *thems_transients = [[self class] ms_transients];
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    
    for (i = 0; i < outCount; i++)
    {
        objc_property_t property = properties[i];
        //获取属性名
        NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        
        if ([thems_transients containsObject:propertyName])
        {
            continue;
        }
        
        [proNames addObject:propertyName];
        //获取属性类型等参数
        NSString *propertyType = [NSString stringWithCString: property_getAttributes(property) encoding:NSUTF8StringEncoding];
        /*
         各种符号对应类型，部分类型在新版SDK中有所变化，如long 和long long
         c char         C unsigned char
         i int          I unsigned int
         l long         L unsigned long
         s short        S unsigned short
         d double       D unsigned double
         f float        F unsigned float
         q long long    Q unsigned long long
         B BOOL
         @ 对象类型 //指针 对象类型 如NSString 是@“NSString”
         
         
         64位下long 和long long 都是Tq
         SQLite 默认支持五种数据类型TEXT、INTEGER、REAL、BLOB、NULL
         因为在项目中用的类型不多，故只考虑了少数类型
         */
        if ([propertyType hasPrefix:@"T@\"NSData"])
        {
            [proTypes addObject:SQLBLOB];
        }
        else if ([propertyType hasPrefix:@"T@"])
        {
            [proTypes addObject:SQLTEXT];
        } 
        else if ([propertyType hasPrefix:@"Ti"] ||
                 [propertyType hasPrefix:@"TI"] ||
                 [propertyType hasPrefix:@"Ts"] ||
                 [propertyType hasPrefix:@"TS"] ||
                 [propertyType hasPrefix:@"TB"] ||
                 [propertyType hasPrefix:@"Tq"] ||
                 [propertyType hasPrefix:@"TQ"])
        {
            [proTypes addObject:SQLINTEGER];
        } 
        else
        {
            [proTypes addObject:SQLREAL];
        }
        
    }
    
    free(properties);
    
    return [NSDictionary dictionaryWithObjectsAndKeys:proNames, @"name", proTypes, @"type", nil];
}
/** 获取所有属性，包含主键pk */
+ (NSDictionary *)ms_getAllProperties
{
    NSDictionary *dict = [self.class ms_getPropertys];
    
    NSMutableArray *proNames = [NSMutableArray array];
    NSMutableArray *proTypes = [NSMutableArray array];
    [proNames addObject:primaryId];
    [proTypes addObject:[NSString stringWithFormat:@"%@ %@", SQLINTEGER, PrimaryKey]];
    [proNames addObjectsFromArray:[dict objectForKey:@"name"]];
    [proTypes addObjectsFromArray:[dict objectForKey:@"type"]];
    
    return [NSDictionary dictionaryWithObjectsAndKeys:proNames, @"name", proTypes, @"type", nil];
}
/** 数据库中是否存在表 */
+ (BOOL)ms_isExistInTable
{
    __block BOOL res = NO;
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    
    [jkDB.dbQueue inDatabase:^(FMDatabase *db) {
        
        NSString *tableName = NSStringFromClass(self.class);
         res = [db tableExists:tableName];
    }];
    
    return res;
}
/** 获取列名 */
+ (NSArray *)ms_getColumns
{
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    NSMutableArray *columns = [NSMutableArray array];
    
     [jkDB.dbQueue inDatabase:^(FMDatabase *db) {
         
         NSString *tableName = NSStringFromClass(self.class);
         FMResultSet *resultSet = [db getTableSchema:tableName];
         
         while ([resultSet next])
         {
             NSString *column = [resultSet stringForColumn:@"name"];
             [columns addObject:column];
         }
     }];
    
    return [columns copy];
}


#pragma mark - insert
/** 保存单个数据 */
- (BOOL)save
{
    NSString *tableName = NSStringFromClass(self.class);
    NSMutableString *keyString = [NSMutableString string];
    NSMutableString *valueString = [NSMutableString string];
    NSMutableArray *insertValues = [NSMutableArray  array];
    
    for (int i = 0; i < self.columeNames.count; i++)
    {
        NSString *proname = [self.columeNames objectAtIndex:i];
        
        if ([proname isEqualToString:primaryId])
        {
            continue;
        }
        
        [keyString appendFormat:@"%@,", proname];
        [valueString appendString:@"?,"];
        id value = [self valueForKey:proname];
        
        if (!value)
        {
            value = @"";
        }
        
        [insertValues addObject:value];
    }
    
    [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)];
    [valueString deleteCharactersInRange:NSMakeRange(valueString.length - 1, 1)];
    
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    __block BOOL res = NO;
    
    [jkDB.dbQueue inDatabase:^(FMDatabase *db) {
        
        NSString *sql = [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES (%@);", tableName, keyString, valueString];
        res = [db executeUpdate:sql withArgumentsInArray:insertValues];
        self.pk = res?[NSNumber numberWithLongLong:db.lastInsertRowId].intValue:0;
        MSLog(res ? @"插入成功" : @"插入失败");
    }];
    
    return res;
}
/** 批量保存用户对象 */
+ (BOOL)ms_saveObjects:(NSArray *)array
{
    //判断是否是JKBaseModel的子类
    for (MSDataBaseModel *model in array) 
    {
        if (![model isKindOfClass:[MSDataBaseModel class]])
        {
            return NO;
        }
    }
    
    __block BOOL res = YES;
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    
    // 如果要支持事务
    [jkDB.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        
        for (MSDataBaseModel *model in array)
        {
            NSString *tableName = NSStringFromClass(model.class);
            NSMutableString *keyString = [NSMutableString string];
            NSMutableString *valueString = [NSMutableString string];
            NSMutableArray *insertValues = [NSMutableArray  array];
            
            for (int i = 0; i < model.columeNames.count; i++) 
            {
                NSString *proname = [model.columeNames objectAtIndex:i];
                
                if ([proname isEqualToString:primaryId])
                {
                    continue;
                }
                
                [keyString appendFormat:@"%@,", proname];
                [valueString appendString:@"?,"];
                id value = [model valueForKey:proname];
                
                if (!value)
                {
                    value = @"";
                }
                
                [insertValues addObject:value];
            }
            [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)];
            [valueString deleteCharactersInRange:NSMakeRange(valueString.length - 1, 1)];
            
            NSString *sql = [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES (%@);", tableName, keyString, valueString];
            BOOL flag = [db executeUpdate:sql withArgumentsInArray:insertValues];
            model.pk = flag?[NSNumber numberWithLongLong:db.lastInsertRowId].intValue:0;
            MSLog(flag ? @"插入成功" : @"插入失败");
            
            if (!flag)
            {
                res = NO;
                *rollback = YES;
                
                return;
            }
        }
    }];
    
    return res;
}


#pragma mark - update
/** 更新单个对象 */
- (BOOL)ms_update
{
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    __block BOOL res = NO;
    
    [jkDB.dbQueue inDatabase:^(FMDatabase *db) {
        
        NSString *tableName = NSStringFromClass(self.class);
        id primaryValue = [self valueForKey:primaryId];
        
        if (!primaryValue || primaryValue <= 0)
        {
            return ;
        }
        
        NSMutableString *keyString = [NSMutableString string];
        NSMutableArray *updateValues = [NSMutableArray  array];
        
        for (int i = 0; i < self.columeNames.count; i++) {
            
            NSString *proname = [self.columeNames objectAtIndex:i];
            
            if ([proname isEqualToString:primaryId])
            {
                continue;
            }
            
            [keyString appendFormat:@" %@=?,", proname];
            id value = [self valueForKey:proname];
            
            if (!value)
            {
                value = @"";
            }
            [updateValues addObject:value];
        }
        
        //删除最后那个逗号
        [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)];
        NSString *sql = [NSString stringWithFormat:@"UPDATE %@ SET %@ WHERE %@ = ?;", tableName, keyString, primaryId];
        [updateValues addObject:primaryValue];
        res = [db executeUpdate:sql withArgumentsInArray:updateValues];
        MSLog(res ? @"更新成功" : @"更新失败");
    }];
    
    return res;
}
/** 批量更新用户对象*/
+ (BOOL)ms_updateObjects:(NSArray *)array
{
    for (MSDataBaseModel *model in array)
    {
        if (![model isKindOfClass:[MSDataBaseModel class]])
        {
            return NO;
        }
    }
    
    __block BOOL res = YES;
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    
    // 如果要支持事务
    [jkDB.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        
        for (MSDataBaseModel *model in array)
        {
            NSString *tableName = NSStringFromClass(model.class);
            id primaryValue = [model valueForKey:primaryId];
            
            if (!primaryValue || primaryValue <= 0)
            {
                res = NO;
                *rollback = YES;
                return;
            }
            
            NSMutableString *keyString = [NSMutableString string];
            NSMutableArray *updateValues = [NSMutableArray  array];
            
            for (int i = 0; i < model.columeNames.count; i++)
            {
                NSString *proname = [model.columeNames objectAtIndex:i];
                
                if ([proname isEqualToString:primaryId])
                {
                    continue;
                }
                
                [keyString appendFormat:@" %@=?,", proname];
                id value = [model valueForKey:proname];
                
                if (!value)
                {
                    value = @"";
                }
                
                [updateValues addObject:value];
            }
            
            //删除最后那个逗号
            [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)];
            NSString *sql = [NSString stringWithFormat:@"UPDATE %@ SET %@ WHERE %@=?;", tableName, keyString, primaryId];
            [updateValues addObject:primaryValue];
            BOOL flag = [db executeUpdate:sql withArgumentsInArray:updateValues];
            MSLog(flag ? @"更新成功" : @"更新失败");
            
            if (!flag)
            {
                res = NO;
                *rollback = YES;
                return;
            }
        }
    }];
    
    return res;
}


#pragma mark - insert/update
/** 保存或更新
 * 如果不存在主键，保存，
 * 有主键，则更新
 */
- (BOOL)ms_saveOrUpdate
{
    id primaryValue = [self valueForKey:primaryId];
    
    if ([primaryValue intValue] <= 0)
    {
        return [self save];
    }
    
    return [self ms_update];
}
/** 保存或更新
 * 如果根据特定的列数据可以获取记录，则更新，
 * 没有记录，则保存
 */
- (BOOL)ms_saveOrUpdateByColumnName:(NSString*)columnName AndColumnValue:(NSString*)columnValue
{
    id record = [self.class ms_findFirstByCriteria:[NSString stringWithFormat:@"where %@ = %@",columnName,columnValue]];
    
    if (record)
    {
        id primaryValue = [record valueForKey:primaryId]; //取到了主键PK
        
        if ([primaryValue intValue] <= 0)
        {
            return [self save];
        }
        else
        {
            self.pk = [primaryValue integerValue];
            
            return [self ms_update];
        }
    }
    else
    {
        return [self save];
    }
}


#pragma mark - delete
/** 删除单个对象 */
- (BOOL)ms_deleteObject
{
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    __block BOOL res = NO;
    
    [jkDB.dbQueue inDatabase:^(FMDatabase *db) {
        
        NSString *tableName = NSStringFromClass(self.class);
        id primaryValue = [self valueForKey:primaryId];
        
        if (!primaryValue || primaryValue <= 0)
        {
            return;
        }
        
        NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = ?",tableName,primaryId];
        res = [db executeUpdate:sql withArgumentsInArray:@[primaryValue]];
        MSLog(res ? @"删除成功" : @"删除失败");
    }];
    
    return res;
}
/** 批量删除用户对象 */
+ (BOOL)ms_deleteObjects:(NSArray *)array
{
    for (MSDataBaseModel *model in array)
    {
        if (![model isKindOfClass:[MSDataBaseModel class]])
        {
            return NO;
        }
    }
    
    __block BOOL res = YES;
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    
    // 如果要支持事务
    [jkDB.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        
        for (MSDataBaseModel *model in array)
        {
            NSString *tableName = NSStringFromClass(model.class);
            id primaryValue = [model valueForKey:primaryId];
            
            if (!primaryValue || primaryValue <= 0)
            {
                return ;
            }
            
            NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = ?",tableName,primaryId];
            BOOL flag = [db executeUpdate:sql withArgumentsInArray:@[primaryValue]];
            MSLog(flag ? @"删除成功" : @"删除失败");
            
            if (!flag)
            {
                res = NO;
                *rollback = YES;
                return;
            }
        }
    }];
    
    return res;
}
/** 通过条件删除数据 */
+ (BOOL)ms_deleteObjectsByCriteria:(NSString *)criteria
{
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    __block BOOL res = NO;
    
    [jkDB.dbQueue inDatabase:^(FMDatabase *db) {
        
        NSString *tableName = NSStringFromClass(self.class);
        NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ %@ ",tableName,criteria];
        res = [db executeUpdate:sql];
        MSLog(res ? @"删除成功" : @"删除失败");
    }];
    
    return res;
}
/** 通过条件删除 (多参数）--2 */
+ (BOOL)ms_deleteObjectsWithFormat:(NSString *)format, ...
{
    va_list ap;
    va_start(ap, format);
    NSString *criteria = [[NSString alloc] initWithFormat:format locale:[NSLocale currentLocale] arguments:ap];
    va_end(ap);
    
    return [self ms_deleteObjectsByCriteria:criteria];
}
/** 清空表 */
+ (BOOL)ms_clearTable
{
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    __block BOOL res = NO;
    
    [jkDB.dbQueue inDatabase:^(FMDatabase *db) {
        
        NSString *tableName = NSStringFromClass(self.class);
        NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@",tableName];
        res = [db executeUpdate:sql];
        MSLog(res ? @"清空成功" : @"清空失败");
    }];
    
    return res;
}


#pragma mark - query
/** 查询全部数据 */
+ (NSArray *)ms_findAll
{
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    NSMutableArray *users = [NSMutableArray array];
    
    [jkDB.dbQueue inDatabase:^(FMDatabase *db) {
        
        NSString *tableName = NSStringFromClass(self.class);
        NSString *sql = [NSString stringWithFormat:@"SELECT * FROM %@",tableName];
        FMResultSet *resultSet = [db executeQuery:sql];
        
        while ([resultSet next])
        {
            MSDataBaseModel *model = [[self.class alloc] init];
            
            for (int i=0; i< model.columeNames.count; i++)
            {
                NSString *columeName = [model.columeNames objectAtIndex:i];
                NSString *columeType = [model.columeTypes objectAtIndex:i];
                
                if ([columeType isEqualToString:SQLBLOB])
                {
                    [model setValue:[resultSet dataForColumn:columeName] forKey:columeName];
                }
                else if ([columeType isEqualToString:SQLTEXT])
                {
                    [model setValue:[resultSet stringForColumn:columeName] forKey:columeName];
                }
                else
                {
                    [model setValue:[NSNumber numberWithLongLong:[resultSet longLongIntForColumn:columeName]] forKey:columeName];
                }
             }
            
            [users addObject:model];
            FMDBRelease(model);
        }
    }];
    
    MSLog(@"db：%@", [users yy_modelToJSONString]);
    return users;
}
/** 通过条件查找数据
 * 这样可以进行分页查询，例如：@" WHERE pk > 5 limit 10"
 */
+ (NSArray *)ms_findByCriteria:(NSString *)criteria
{
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    NSMutableArray *users = [NSMutableArray array];
    
    [jkDB.dbQueue inDatabase:^(FMDatabase *db) {
        
        NSString *tableName = NSStringFromClass(self.class);
        NSString *sql = [NSString stringWithFormat:@"SELECT * FROM %@ %@", tableName, criteria];
        FMResultSet *resultSet = [db executeQuery:sql];
        
        while ([resultSet next])
        {
            MSDataBaseModel *model = [[self.class alloc] init];
            for (int i=0; i< model.columeNames.count; i++)
            {
                NSString *columeName = [model.columeNames objectAtIndex:i];
                NSString *columeType = [model.columeTypes objectAtIndex:i];
                
                if ([columeType isEqualToString:SQLBLOB])
                {
                    [model setValue:[resultSet dataForColumn:columeName] forKey:columeName];
                }
                else if ([columeType isEqualToString:SQLTEXT])
                {
                    [model setValue:[resultSet stringForColumn:columeName] forKey:columeName];
                }
                else
                {
                    [model setValue:[NSNumber numberWithLongLong:[resultSet longLongIntForColumn:columeName]] forKey:columeName];
                }
            }
            
            [users addObject:model];
            FMDBRelease(model);
        }
    }];
    
    MSLog(@"db：%@", [users yy_modelToJSONString]);
    return users;
}
/** 通过条件查找数据 */
+ (NSArray *)ms_findWithFormat:(NSString *)format, ...
{
    va_list ap;
    va_start(ap, format);
    NSString *criteria = [[NSString alloc] initWithFormat:format locale:[NSLocale currentLocale] arguments:ap];
    va_end(ap);
    
    return [self ms_findByCriteria:criteria];
}
/** 通过条件查找第一个数据，例如：@" WHERE pk > 5 limit 10" */
+ (instancetype)ms_findFirstByCriteria:(NSString *)criteria
{
    NSArray *results = [self.class ms_findByCriteria:criteria];
    
    if (results.count < 1)
    {
        return nil;
    }
    
    return [results firstObject];
}
/** 查询全部数据 */
+ (instancetype)ms_findAll:(int)inPk
{
    NSString *condition = [NSString stringWithFormat:@"WHERE %@=%d", primaryId, inPk];
    
    return [self ms_findFirstByCriteria:condition];
}
/** 通过条件查找第一个数据 */
+ (instancetype)ms_findFirstWithFormat:(NSString *)format, ...
{
    va_list ap;
    va_start(ap, format);
    NSString *criteria = [[NSString alloc] initWithFormat:format locale:[NSLocale currentLocale] arguments:ap];
    va_end(ap);
    
    return [self ms_findFirstByCriteria:criteria];
}


#pragma mark - create table
/**
 * 创建表 / 添加新的列
 * 成功返回YES
 */
+ (BOOL)ms_createTable
{
    __block BOOL res = YES;
    MSDataBaseModelHelp *jkDB = [MSDataBaseModelHelp shareInstance];
    
    [jkDB.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        
        NSString *tableName = NSStringFromClass(self.class);
        NSString *columeAndType = [self.class getColumeAndTypeString];
        NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@(%@);",tableName,columeAndType];
        
        if (![db executeUpdate:sql])
        {
            res = NO;
            *rollback = YES;
            return;
        };
        
        // 有新属性时往表中添加新列
        NSMutableArray *columns = [NSMutableArray array];
        FMResultSet *resultSet = [db getTableSchema:tableName];
        
        while ([resultSet next])
        {
            NSString *column = [resultSet stringForColumn:@"name"];
            [columns addObject:column];
        }
        NSDictionary *dict = [self.class ms_getAllProperties];
        NSArray *properties = [dict objectForKey:@"name"];
        /// 判断是否包含队列谓词
        NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)",columns];
        //过滤数组
        NSArray *resultArray = [properties filteredArrayUsingPredicate:filterPredicate];
        
        for (NSString *column in resultArray)
        {
            NSUInteger index = [properties indexOfObject:column];
            NSString *proType = [[dict objectForKey:@"type"] objectAtIndex:index];
            NSString *fieldSql = [NSString stringWithFormat:@"%@ %@",column,proType];
            ///在表中添加列
            NSString *sql = [NSString stringWithFormat:@"ALTER TABLE %@ ADD COLUMN %@ ",NSStringFromClass(self.class),fieldSql];
            
            if (![db executeUpdate:sql])
            {
                res = NO;
                *rollback = YES;
                
                return ;
            }
        }
    }];
    
    return res;
}


#pragma mark - must be override method
/** 如果子类中有一些property不需要创建数据库字段，那么这个方法必须在子类中重写
 */
+ (NSArray *)ms_transients
{
    return [NSArray array];
}


@end


#pragma mark - 辅助类
@interface MSDataBaseModelHelp()

/** 数据存储队列*/
@property (nonatomic, retain) FMDatabaseQueue *dbQueue;

@end

@implementation MSDataBaseModelHelp

static MSDataBaseModelHelp *_instance = nil;

/** 更改db文件夹名称
 * directoryName 文件夹名称
 */
- (BOOL)ms_changeDBWithDirectoryName:(NSString *)directoryName
{
    if (_instance.dbQueue) 
    {
        _instance.dbQueue = nil;
    }
    
    _instance.dbQueue = [[FMDatabaseQueue alloc] initWithPath:[MSDataBaseModelHelp ms_dbPathWithDirectoryName:directoryName]];
    
    int numClasses;
    Class *classes = NULL;
    // 1.获取当前app运行时所有的类，包括系统创建的类和开发者创建的类的  个数
    numClasses = objc_getClassList(NULL,0);
    
    if (numClasses >0 )
    {
        // 2.创建一个可以容纳numClasses个的大小空间
        classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
        // 3.重新获取具体类的列表和个数
        numClasses = objc_getClassList(classes, numClasses);
        // 4.遍历
        for (int i = 0; i < numClasses; i++)
        {
            // 5.找出数据类MSDataBaseModel
            if (class_getSuperclass(classes[i]) == [MSDataBaseModel class])
            {
                id class = classes[i];
                // 6.创建表
                [class performSelector:@selector(ms_createTable) withObject:nil];
            }
        }
        
        free(classes);
    }
    
    return YES;
}
/** db文件路径 ~/MSBD/msdb.sqlite
 * directoryName 文件夹名称，默认为MSBD
 */
+ (NSString *)ms_dbPathWithDirectoryName:(NSString *)directoryName
{
    NSString *docsdir = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSFileManager *filemanage = [NSFileManager defaultManager];
    
    if (directoryName == nil || directoryName.length == 0)
    {
        docsdir = [docsdir stringByAppendingPathComponent:@"MSBD"];
    } 
    else
    {
        docsdir = [docsdir stringByAppendingPathComponent:directoryName];
    }
    
    BOOL isDir;
    BOOL exit =[filemanage fileExistsAtPath:docsdir isDirectory:&isDir];
    
    if (!exit || !isDir)
    {
        [filemanage createDirectoryAtPath:docsdir withIntermediateDirectories:YES attributes:nil error:nil];
    }
    
    NSString *dbPath = [docsdir stringByAppendingPathComponent:@"msdb.sqlite"];
    MSLog(@"dbPath：%@", dbPath);
    
    return dbPath;
}
/** 数据存储队列*/
- (FMDatabaseQueue *)dbQueue
{
    if (_dbQueue == nil) 
    {
        _dbQueue = [[FMDatabaseQueue alloc] initWithPath:[self.class ms_dbPathWithDirectoryName:nil]];
    }
    return _dbQueue;
}

+ (instancetype)shareInstance
{
    static dispatch_once_t onceToken ;
    
    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone:NULL] init];
    });
    
    return _instance;
}
+ (id)allocWithZone:(struct _NSZone *)zone
{
    return [MSDataBaseModelHelp shareInstance];
}

- (id)copyWithZone:(struct _NSZone *)zone
{
    return [MSDataBaseModelHelp shareInstance];
}


@end
